﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Text;
using System.Threading.Tasks;
using Abp.Application.Services.Dto;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Camc.Duct.TaskProcess.Dto;
using Camc.Duct.TaskProcess.Dto.Statistics;
using Camc.Duct.TaskProcess.Process;
using Camc.Duct.TaskProcess.Request;
using Camc.Duct.TaskProcess.Station;
using Camc.Duct.TaskProcess.TaskLine;
using Castle.Components.DictionaryAdapter;
using IdentityServer4.Services;
using Microsoft.EntityFrameworkCore;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;

namespace Camc.Duct.TaskProcess
{
	public class StatisticsAppService: DuctAppServiceBase
	{
		private readonly IRepository<NodeBase, long> _nodeBaseRepository;
		private readonly IRepository<NodeForTemplate, long> _nodeForTemplateRepository;
		private readonly IRepository<LineTemplate, Guid> _lineTemplateRepository;
		private readonly IRepository<WorkStation, Guid> _workStationRepository;
		private readonly IRepository<NodeForInstance, long> _nodeForInstanceRepository;
		private readonly IRepository<LineInstance, Guid> _lineInstanceRepository;
		private readonly IRepository<RequestBase, long> _requestBaseRepository;
		private readonly IRepository<LineInstanceExecuteHistory, long> _lineInstanceExecuteHistoryRepository;
		

		public StatisticsAppService(IRepository<NodeBase, long> nodeBaseRepository,
			IRepository<NodeForTemplate, long> nodeForTemplateRepository,
			IRepository<LineTemplate, Guid> lineTemplateRepository,
			IRepository<WorkStation, Guid> workStationRepository,
			IRepository<NodeForInstance, long> nodeForInstanceRepository,
			IRepository<LineInstance, Guid> lineInstanceRepository, IRepository<RequestBase, long> requestBaseRepository, IRepository<LineInstanceExecuteHistory, long> lineInstanceExecuteHistoryRepository)
		{
			_nodeBaseRepository = nodeBaseRepository;
			_nodeForTemplateRepository = nodeForTemplateRepository;
			_lineTemplateRepository = lineTemplateRepository;
			_workStationRepository = workStationRepository;
			_nodeForInstanceRepository = nodeForInstanceRepository;
			_lineInstanceRepository = lineInstanceRepository;
			_requestBaseRepository = requestBaseRepository;
			_lineInstanceExecuteHistoryRepository = lineInstanceExecuteHistoryRepository;
		}


		public NumberOfSummary GetSummary()
		{
			var output = new NumberOfSummary();

			output.InlineNum = _lineInstanceRepository
				.GetAll().Count(c => c.State != TaskLineState.完成 && c.State != TaskLineState.报废);
			output.InlineNumForComplete = _lineInstanceRepository.GetAll().Count(c =>
				c.State == TaskLineState.完成 && c.LastModificationTime > DateTime.Now.AddMonths(-1));
			output.InlineNumForRequest = _lineInstanceRepository.GetAll().Count(c =>
				c.State == TaskLineState.暂停 );
			output.InlineNumForScrap = _lineInstanceRepository.GetAll().Count(c =>
				c.State == TaskLineState.报废 && c.LastModificationTime > DateTime.Now.AddMonths(-1));

			return output;
		}

		public List<KeyValuePair<string,int>> GetSummaryForModel()
		{
			var modelGroup = _lineInstanceRepository.GetAll().Where(c => c.State != TaskLineState.完成 && c.State!= TaskLineState.报废)
				.GroupBy(c => c.TaskModel).Select(o => new KeyValuePair<string, int>(o.Key, o.Sum(c => c.Quantity)))
				.ToList();

			return modelGroup;
		}

		public List<NumberOfProcess> GetSummaryForProcess()
        {
            var processGroup = _nodeForInstanceRepository.GetAll()
                .GroupBy(c => new{ c.NodeName,c.OrderIndex })
                .Select(o => new {ProcessName = o.Key.NodeName,index=o.Key.OrderIndex})
                .OrderBy(p=>p.index);

			var instanceWithCurrentProcess = _lineInstanceRepository
				.GetAllIncluding(c => c.InstanceNodeList, d => d.Historys)
				.Where(c => c.State != TaskLineState.完成 && c.State != TaskLineState.报废)
				.Select(c=>new 
					{
						CurrentProcessName = (c.InstanceNodeList.FirstOrDefault(e =>
							e.OrderIndex ==
							c.Historys.OrderByDescending(d => d.CreationTime)
								.FirstOrDefault().OrderIndex)).NodeName,
						Quantity = c.Quantity,
						State = c.State,
						Exceeded = c.Historys.OrderByDescending(d => d.OrderIndex).FirstOrDefault().CreationTime.AddHours(ProcessConsts.ExceedHourLimit) < DateTime.Now

				}
				);

			var numberOfProcess = processGroup.GroupJoin(instanceWithCurrentProcess, o => o.ProcessName,
				p => p.CurrentProcessName,

                (allProcess, currentInstance) => new NumberOfProcess
				{
					ProcessName = allProcess.ProcessName,
					NumberForAll = currentInstance.Sum(q => q.Quantity),
                    NumberForTask = currentInstance.Count(),
					NumberForPause = currentInstance.Where(k => k.State == TaskLineState.暂停).Sum(l => l.Quantity),
					NumberForExceedTime = currentInstance.Where(k => k.Exceeded).Sum(c=>c.Quantity)
				}).ToList();

			return numberOfProcess;
		}
		public List<GetAllRequestOutput> GetRecentlyRequestion()
		{
			var query = _requestBaseRepository.GetAll();


			var groupJoin = query.GroupJoin(_lineInstanceRepository.GetAll(),
				o => o.LineInstanceId,
				p => p.Id,
				(request, instance) => new GetAllRequestOutput
				{
					Id = request.Id,
					InstanceId = request.LineInstanceId,
					Model = instance.FirstOrDefault().TaskModel,
					DrawingCode = instance.FirstOrDefault().ProductionDrawingCode,
					CreationTime = request.CreationTime,
					RequesterId = request.RequesterId,
					Responder = request.Responder,
					RequestInfo = request.RequestInfo,
					RespondInfo = request.RespondInfo,
					RespondOperation = request.RespondOperation,
					RespondTime = request.RespondTime
				}
			).OrderByDescending(c=>c.CreationTime).Take(10).ToList();


			return groupJoin;

		}

		public List<GetRecentlyDeliveryOutput> GetRecentlyDelivery(int takeNum)
		{
			var query = _lineInstanceRepository.GetAll().Where(c=>c.State == TaskLineState.完成).OrderByDescending(c=>c.LastModificationTime);


			var output = query.Select(
				c => new GetRecentlyDeliveryOutput
				{
					CompleteTime = (DateTime)c.LastModificationTime,
					DeliveryTime = c.DeliveryTime,
					DrawingCode = c.ProductionDrawingCode,
					Model = c.TaskModel
				}
			).Take(takeNum).ToList();

			return output;
		}


		//停留时长任务排序
		public PagedResultDto<GetLineInstanceForExecuteOutput> GetAllLineInstanceOrderByDuration(
			GetLineInstanceForExecuteInput input)
		{
			var query = _lineInstanceRepository.GetAllIncluding(c => c.InstanceNodeList, d => d.Historys, e => e.WorkingTeam).Where(c => c.IsDeleted == false);

			query = query.Where(c=>c.State == TaskLineState.进行 || c.State == TaskLineState.暂停);

			var ouputs = query.Select(c => new GetLineInstanceForExecuteOutput()
			{
				CurrentStationName = c.InstanceNodeList.FirstOrDefault(d =>
						d.OrderIndex == c.Historys.OrderByDescending(f => f.CreationTime).FirstOrDefault().OrderIndex)
					.NodeName,
				ProductionDrawingCode = c.ProductionDrawingCode,
				ProductionSpecial = c.ProductionSpecial,
				Id = c.Id,
				StateDisplayText = c.State.ToString(),
				TaskModel = c.TaskModel,
				Quantity = c.Quantity,
				DeliveryTime = c.DeliveryTime,
				WorkingTeamName = c.WorkingTeam.DisplayName,
				LastExecutionTime = c.Historys.OrderByDescending(f => f.CreationTime).FirstOrDefault().StartTime
				
			}).OrderBy(c=> c.LastExecutionTime);


			var count = ouputs.Count();

			var lineInstances = ouputs
				.PageBy(input)
				.ToList();

			return new PagedResultDto<GetLineInstanceForExecuteOutput>(
				count,
				lineInstances
			);
		}


		//型号返工及报废数量比例计算
		public List<GetReturnAndScrapGroupByModelOutput> GetReturnAndScrapGroupByModel()
		{
			var output = 
				_lineInstanceRepository.GetAllIncluding(c=>c.RequestBaseList)
					.Where(c=>c.IsDeleted == false)
				.GroupBy(c => c.TaskModel)
				.Select(c => new GetReturnAndScrapGroupByModelOutput
				{
					ModelName = c.Key,
					ScrapCount = c.Where(d=>d.State == TaskLineState.报废).Sum(d=>d.Quantity),
					ScrapRatio = c.Where(d => d.State == TaskLineState.报废).Sum(d => d.Quantity) / c.Sum(d => d.Quantity),
					//返工的计算方法，目前出现问题就算返工
					ReturnRatio = c.Where(d=>d.RequestBaseList.Count!=0).Sum(d => d.Quantity) / c.Sum(d => d.Quantity),
					ReturnCount = c.Where(d => d.RequestBaseList.Count != 0).Sum(d => d.Quantity)
				});


			return output.ToList();
		}


		//各班组月份任务统计
		public List<GetAllInfoOfWorkingTeamsOutput> GetAllInfoOfWorkingTeams(int fromLastMonthCount,params int[] stationList)
		{
			int[] workStationIdList = stationList;//出库，内窥，弯管，焊接的orderindex

			var output = new List<GetAllInfoOfWorkingTeamsOutput>();

			if (fromLastMonthCount <1 || fromLastMonthCount.Equals(null))
			{
				fromLastMonthCount = 1;
			}


			var beginTime = DateTime.Now.AddMonths(-1);
			beginTime = new DateTime(beginTime.Year, beginTime.Month, 1);

			var allExecuteHistoriesInDuration = _lineInstanceExecuteHistoryRepository.GetAll()
				.Where(c => c.StartTime >= beginTime && c.StartTime < DateTime.Now);

			var executeForTeam = allExecuteHistoriesInDuration.GroupJoin(_lineInstanceRepository.GetAll(),
				c => c.LineInstanceId, 
				d => d.Id,
				(execution, instance) => new 
				{
					NodeIndex = execution.OrderIndex,
					MonthString = execution.StartTime.Year + "." +execution.StartTime.Month,
					WorkingTeamId = instance.FirstOrDefault().WorkingTeamId,
					InstanceId = instance.FirstOrDefault().Id,
					Count = instance.FirstOrDefault().Quantity
				}
			).GroupBy(c=>c.MonthString+c.WorkingTeamId+c.NodeIndex)
				.Select(c=>new
				{
					Id = c.Key,
					NodeIndex = c.FirstOrDefault().NodeIndex,
					WorkingTeamId = c.FirstOrDefault().WorkingTeamId,
					MonthString = c.FirstOrDefault().MonthString,
					Amount = c.Sum(d=>d.Count)
				})
				.Where(c=> workStationIdList.Contains(c.NodeIndex) && c.WorkingTeamId != null)
				.ToList();

			var allWorkteam = executeForTeam.GroupBy(c => c.WorkingTeamId).Select(c=>c.Key);

			foreach(var teamId in allWorkteam)
			{
				output.AddRange(  executeForTeam.Where(c=>c.WorkingTeamId == teamId).GroupBy(c => c.MonthString).Select(c => new GetAllInfoOfWorkingTeamsOutput
				{
					key = c.FirstOrDefault().Id,
					MonthString = c.FirstOrDefault().MonthString,
					WorkingTeamId = c.FirstOrDefault().WorkingTeamId,
					OutStoreConut = c.Where(d => d.NodeIndex == workStationIdList[0]).Sum(d => d.Amount),
					EndoscopyConut = c.Where(d => d.NodeIndex == workStationIdList[1]).Sum(d => d.Amount),
					BendDuctConut = c.Where(d => d.NodeIndex == workStationIdList[2]).Sum(d => d.Amount),
					WeldConut = c.Where(d => d.NodeIndex == workStationIdList[3]).Sum(d => d.Amount)
				}).ToList());

			}
			//output = executeForTeam.Select(c => new GetAllInfoOfWorkingTeamsOutput
			//{
			//	key = c.Id,
			//	MonthString = c.MonthString,
			//	WorkingTeamId = c.WorkingTeamId,
			//	OutStoreConut = executeForTeam.Where(d=>d.NodeIndex == workStationIdList[0] ).Sum(d=>d.Amount),
			//	EndoscopyConut = executeForTeam.Where(d => d.NodeIndex == workStationIdList[1]).Sum(d => d.Amount),
			//	BendDuctConut = executeForTeam.Where(d => d.NodeIndex == workStationIdList[2]).Sum(d => d.Amount),
			//	WeldConut = executeForTeam.Where(d => d.NodeIndex == workStationIdList[3]).Sum(d => d.Amount)
			//}).ToList();


			return output.ToList();
		}

	}

}
